#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

// 对于sockaddr_in类型的结构体什么时候进行初始化：1.服务器在bind之前要进行绑定 2.UDP收发信息之前要进行绑定

// 启动方式: ./udpclient server_ip server_port
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cerr << "Please Entry Like: ./udpclient server_ip server_port!" << std::endl;
        return 1;
    }

    // 1.创建socket
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    // 2.客户端与服务器不同之处：客户端也需要进行绑定，但是server要显示的进行绑定，客户端OS会进行绑定。
    //                         OS知道客户端的IP和端口号

    std::string sip = (char *)argv[1];
    uint16_t sport = std::stoi(argv[2]);

    // 创建相关的结构体并且清零初始化相关字段
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = sport;
    server.sin_addr.s_addr = inet_addr(sip.c_str());

    socklen_t slen = sizeof(server);
    // while死循环来进行数据的发送和接收
    while (true)
    {
        std::string msg;
        std::cin >> msg;

        int n = sendto(sockfd, msg.c_str(), msg.size(), 0, (struct sockaddr *)&server, slen);

        //定义相关结构体来进行消息的接收
        struct sockaddr_in peer;
        socklen_t plen = sizeof(peer);

        char buf[1024];

        int m = recvfrom(sockfd, buf, sizeof(buf)-1, 0, (struct sockaddr *)&peer, &plen);
        buf[m] = '\0';

        std::cout<<buf<<std::endl;
    }
    return 0;
}